<?php

namespace App\Services\Stats\Platform\Elasticsearch;

use App\Core\Traits\Numeral;
use App\Exports\Stats\Platform\Elasticsearch\SettlementExport;
use App\Exports\Stats\Platform\SettlementUsdExport;
use App\Models\Game\Platform\Org;
use App\Services\Service;
use App\Services\Traits\DatabaseElasticsearch;
use App\Models\Elasticsearch\Settlement\Info as SettlementInfo;
use Helper\Timed;

class SettlementService extends Service
{
	use DatabaseElasticsearch, Numeral;

	/**
	 * 获取数据列表【全部】
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return \Illuminate\Database\Eloquent\Collection[]|int[]|array[]
	 */
	public function all($request, $export = false)
	{
		return $this->getList($request, ['currency','plat_code','line_code'], $export);
	}

	/**
	 * 获取数据列表【游戏】
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return \Illuminate\Database\Eloquent\Collection[]|int[]|array[]
	 */
	public function game($request, $export = false)
	{
		return $this->getList($request, ['currency','plat_code','line_code', 'game_id'], $export);
	}
	/**
	 * 获取游戏统计USD
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return array[]|int[]|array[]
	 */
	public function getList($request, $groupBy, $export = false)
	{
		$params = ['body' => ['size' => 0]];

		// 筛选【状态】
		$this->makeWhere($params, 'status', SettlementInfo::STATUS_NORMAL);
		// 筛选【类型】
		$this->makeWhere($params, 'player_type', SettlementInfo::PLAYER_TYPE);
		// 筛选【平台】
		$this->makeWhereParamOrg($request, $params);
		// 筛选【平台】【排除】
		$this->makeWhereParamNot($request, 'plat_code_exclude', $params, 'plat_code');
		// 筛选【时间】
		$this->makeWhereParamDatetime($request, $params, 'end_time', 'datetime', SettlementInfo::INDEX_NAME);
		// 筛选【游戏】
		$this->makeWhereParam($request, 'game_id', $params);
		// 筛选【游戏】【排除】
		$this->makeWhereParamNot($request, 'game_id_exclude', $params, 'game_id');
		// 筛选【币种】
		$this->makeWhereParam($request, 'currency', $params);
		// 筛选【币种】【排除】
		$this->makeWhereParamNot($request, 'currency_exclude', $params, 'currency');

		$curParams = $params;
		$this->makeGroupAggs($request, $curParams, 'sum', ['bet_base', 'bet_num', 'gain_player'], ['currency']);
		$curParams['body']['aggs']['group']['aggs'] = array_merge($curParams['body']['aggs']['group']['aggs'], $this->makeDistinct('uid'));
		$this->makeAggs($curParams, 'sum', ['usd.bet_base', 'usd.bet_num', 'usd.gain_player']);
		$curParams['body']['aggs'] = array_merge($curParams['body']['aggs'], $this->makeDistinct('uid'));
		$curStat = SettlementInfo::search($curParams);

		// 列表数据
		$this->makeGroupDatetimeAggs($request, $params, 'sum', ['bet_base', 'bet_num', 'gain_player', 'usd.bet_base', 'usd.bet_num', 'usd.gain_player'], $groupBy, "group_str", '1d', 'end_time_at', '*');


		$params['body']['aggs']['group']['aggs'] = array_merge($params['body']['aggs']['group']['aggs'], $this->makeDistinct('uid'));

		//排序
		$order_column = $request->input('order_column', 'bet_base');
		switch ($order_column){
			case "player_count":
				$order_column = 'distinct_uid';
				break;
			case "doc_count":
				$order_column = '_count';
				break;
			case "timed":
				$order_column = '_key';
				break;
		}
		$this->makeAggsOrderParam($request, $params, $order_column);

		$aggStat = SettlementInfo::search($params);
		// 数据条数
		$total = isset($aggStat['aggregations']['group']['buckets']) ? count($aggStat['aggregations']['group']['buckets']) : 0;

		// 导出数据
		if ($export) {
			SettlementExport::array($aggStat['aggregations']['group']['buckets'])->download();
		}

		//分页
		$this->makeAggsPaginationParam($request, $params);


		// 查询数据
		$results = SettlementInfo::search($params);

		// 分页数据
		$stat = $this->makeStats($curStat['aggregations'] ?? null, $request);
		$data = $this->makeList($results['aggregations'] ?? null, $request);

		return [
			$data,
			$total,
			$stat,
		];
	}


	/**
	 * 获取游戏统计USD
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return array[]|int[]|array[]
	 */
	public function getUsd($request, $export = false)
	{
		$params = ['body' => ['size' => 0]];

		// 筛选【状态】
		$this->makeWhere($params, 'status', SettlementInfo::STATUS_NORMAL);
		// 筛选【类型】
		$this->makeWhere($params, 'player_type', SettlementInfo::PLAYER_TYPE);
		// 筛选【平台】
		$this->makeWhereParamOrg($request, $params);
		// 筛选【平台】【排除】
		$this->makeWhereParamNot($request, 'plat_code_exclude', $params, 'plat_code');
		// 筛选【时间】
		$this->makeWhereParamDatetime($request, $params, 'end_time', 'datetime', SettlementInfo::INDEX_NAME);
		// 筛选【游戏】
		$this->makeWhereParam($request, 'game_id', $params);
		// 筛选【游戏】【排除】
		$this->makeWhereParamNot($request, 'game_id_exclude', $params, 'game_id');

		// 统计数据
		$this->makeGroupAggs($request, $params, 'sum', ['bet_base', 'bet_num', 'gain_player', 'usd.bet_base', 'usd.bet_num', 'usd.gain_player'], ['plat_code','line_code'], '', 'datetime', '_');
		$params['body']['aggs']['group']['aggs'] = array_merge($params['body']['aggs']['group']['aggs'], $this->makeDistinct('uid'));


		$this->makeAggs($params, 'sum', ['bet_base', 'bet_num', 'gain_player', 'usd.bet_base', 'usd.bet_num', 'usd.gain_player']);
		$params['body']['aggs'] = array_merge($params['body']['aggs'], $this->makeDistinct('uid'));

		//排序
		$order_column = $request->input('order_column', 'bet_base');
		switch ($order_column){
			case "player_count":
				$order_column = 'distinct_uid';
				break;
			case "doc_count":
				$order_column = '_count';
				break;
			case "bet_base":
				$order_column = 'usd_bet_base';
				break;
			case "bet_num":
				$order_column = 'usd_bet_num';
				break;
			case "gain_player":
				$order_column = 'usd_gain_player';
				break;
		}
		$this->makeAggsOrderParam($request, $params, $order_column);

		// 查询数据
		$results = SettlementInfo::search($params);

		// 统计数据
		$stats = $this->makeStatsUsd($results['aggregations'] ?? null);

		return [
			$stats['data'],
			$stats['usd'],
		];
	}

	private function makeStatsUsd($aggs)
	{
		if (is_null($aggs)) {
			return ['usd' => new \stdClass(), 'data' => []];
		}

		// USD【合计】
		$usd = [
			'gain_player' => $aggs['usd.gain_player']['value'],
			'amount' => -$aggs['usd.gain_player']['value'],
			'bet_base' => $aggs['usd.bet_base']['value'],
			'bet_num' => $aggs['usd.bet_num']['value'],
			'player_count' => $aggs['distinct_uid']['value'],
			'doc_count' => 0,
		];
		// USD【RTP】
		$usd['rtp'] = $this->makeRtp($usd['bet_num'], $usd['gain_player']);

		// 分游戏【合计】
		$data = collect($aggs['group']['buckets'])->map(function ($item)use(&$usd) {
			$usd['doc_count'] += $item['doc_count'];

			return [
				'bet_base' => $item['usd_bet_base']['value'],
				'bet_num' => $item['usd_bet_num']['value'],
				'plat_code' => $item['key']['plat_code'],
				'line_code' => $item['key']['line_code'],
				'doc_count' => $item['doc_count'],
				'gain_player' => $item['usd_gain_player']['value'],
				'amount' => -$item['usd_gain_player']['value'],
				'player_count' => $item['distinct_uid']['value'],
			];
		});

		//查询org
		$plat_codes = array_column($data->toArray(), 'plat_code');
		$orgs = Org::whereIn('code', $plat_codes)->select(['code', 'name'])->get()->toArray();
		$orgArr = array_column($orgs, 'name', 'code');

		// 分币种【RTP】
		$data->transform(function ($item)use($orgArr) {
			return $item + [
					'rtp' => $this->makeRtp($item['bet_num'], $item['gain_player']),
					'org' =>[
						'code' => $item['plat_code'],
						'name' => isset($orgArr[$item['plat_code']]) ? $orgArr[$item['plat_code']] : $item['plat_code'],
					]
				];
		});

		return [
			'usd' => $usd,
			'data' => $data,
		];
	}

	private function makeStats($aggs, $request)
	{
		if (is_null($aggs)) {
			return [
				'usd' => [],
				'sts' => [],
			];
		}

		// USD【合计】
		$usd = [
			'gain_player' => $aggs['usd.gain_player']['value'],
			'amount' => -$aggs['usd.gain_player']['value'],
			'bet_base' => $aggs['usd.bet_base']['value'],
			'bet_num' => $aggs['usd.bet_num']['value'],
			'player_count' => $aggs['distinct_uid']['value'],
			'doc_count' => 0,
		];
		// USD【RTP】
		$usd['rtp'] = $this->makeRtp($usd['bet_num'], $usd['gain_player']);

		// 分游戏分币种【合计】
		$currency = collect($aggs['group']['buckets'])->map(function ($item)use(&$usd) {
			$usd['doc_count'] += $item['doc_count'];
			return [
				'bet_base' => $item['bet_base']['value'],
				'bet_num' => $item['bet_num']['value'],
				'currency' => $item['key']['currency'],
				'doc_count' => $item['doc_count'],
				'gain_player' => $item['gain_player']['value'],
				'player_count' => $item['distinct_uid']['value'],
				'amount' => -$item['gain_player']['value'],
				'rtp' => $this->makeRtp($item['bet_num']['value'], $item['gain_player']['value']),
			];
		});

		return [
			'usd' => $usd,
			'sts' => $currency,
		];
	}

	//分页数据
	private function makeList($aggs, $request)
	{
		if (is_null($aggs)) {
			return [];
		}

		$data = collect($aggs['group']['buckets'])->map(function ($item)use(&$usd, &$currency, $request) {

			$grouopArr = explode('*', rtrim($item['key']['group_str'], '*'));

			return [
				'timed' => $item['key']['timed'],
				'bet_base' => $item['bet_base']['value'],
				'bet_num' => $item['bet_num']['value'],
                'plat_code' => $grouopArr[1],
                'currency' => $grouopArr[0],
                'line_code' => $grouopArr[2],
                'game_id' => isset($grouopArr[3]) ? $grouopArr[3] : '-',
				'doc_count' => $item['doc_count'],
				'amount' => -$item['gain_player']['value'],
				'gain_player' => $item['gain_player']['value'],
				'player_count' => $item['distinct_uid']['value'],
				'usd_amount' => -$item['usd.gain_player']['value'],
				'usd_bet_base' => $item['usd.bet_base']['value'],
				'usd_bet_num' => $item['usd.bet_num']['value'],
				'usd_gain_player' => $item['usd.gain_player']['value'],
				'rtp' => $this->makeRtp($item['bet_num']['value'], $item['gain_player']['value']),
				'usd'=>
					[
						'amount' => -$item['usd.gain_player']['value'],
						'bet_base' => $item['usd.bet_base']['value'],
						'bet_num' => $item['usd.bet_num']['value'],
						'gain_player' => $item['usd.gain_player']['value'],
					],
				'time_zone' => Timed::getTimeCode(),
			];
		});

		//查询org
		$plat_codes = array_column($data->toArray(), 'plat_code');
		$orgs = Org::whereIn('code', $plat_codes)->select(['code', 'name'])->get()->toArray();
		$orgArr = array_column($orgs, 'name', 'code');

		// 分币种【RTP】
		$data->transform(function ($item)use($orgArr) {
			return $item + [
					'org' =>[
						'code' => $item['plat_code'],
						'name' => isset($orgArr[$item['plat_code']]) ? $orgArr[$item['plat_code']] : $item['plat_code'],
					]
				];
		});

		return $data;
	}
}
